package just.stuff.morsels.ui.label;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.zip.CRC32;

import just.stuff.morsels.MorselApplication;
import just.stuff.morsels.objects.Morsel;

import org.apache.wicket.markup.html.IHeaderContributor;
import org.apache.wicket.markup.html.IHeaderResponse;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.util.template.PackagedTextTemplate;
import org.apache.wicket.util.template.TextTemplate;

public class LabelGraphPanel extends Panel implements IHeaderContributor {

	private String label;
	
	public LabelGraphPanel( String id, String label ) {
		super( id );
		this.label = label;
	}

	private static class LabelEdge {
		private String one;
		private String two;
		
		public LabelEdge( String first, String second ) {
			if( first.compareTo( second ) > 0 ) {
				one = second;
				two = first;
			} else {
				one = first;
				two = second;
			}
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((one == null) ? 0 : one.hashCode());
			result = prime * result + ((two == null) ? 0 : two.hashCode());
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			LabelEdge other = (LabelEdge) obj;
			if (one == null) {
				if (other.one != null)
					return false;
			} else if (!one.equals(other.one))
				return false;
			if (two == null) {
				if (other.two != null)
					return false;
			} else if (!two.equals(other.two))
				return false;
			return true;
		}
		
		
		
	}
	
	
	public void renderHead(IHeaderResponse response) {
		HashMap<LabelEdge, Integer> edges = new HashMap<LabelEdge, Integer>();
		List<Morsel> morsels = MorselApplication.dataSource().morsels();
		HashMap< String, Integer> labelSizes = new HashMap<String, Integer>();
		for( Morsel m : morsels ) {
			if( m.getLabels() != null && !m.isRoot() ) {
				String [] labels = m.getLabels().toArray( new String[0]);
				for( int i = 0; i < labels.length; i++ ) {
					inc( labelSizes, labels[ i ] );
					for( int j = 0; j < i; j++ ) {
						LabelEdge edge = new LabelEdge( labels[ i ], labels[ j ] );
						inc( edges, edge );
					}
				}
			}
		}

		int minMorsel = Integer.MAX_VALUE;
		int maxMorsel = Integer.MIN_VALUE;
		for(  Integer value : labelSizes.values() ) {
			if( value < minMorsel )
				minMorsel = value;
			if( value > maxMorsel )
				maxMorsel = value;
		}
		
		
		TextTemplate tt = new PackagedTextTemplate( this.getClass(), "labelGraph.js" );
		Map<String,Object> vars = new HashMap<String, Object>();
		StringBuilder sb = new StringBuilder();
		for( String label : labelSizes.keySet() ) {
			double ratio = (double)(labelSizes.get( label ) - minMorsel ) / (double)(maxMorsel - minMorsel + 1 );
			if( maxMorsel == minMorsel ) {
				ratio = 1.0;
			}
			int size = (int)Math.round( 16.0 * ratio ) + 1;
			CRC32 crc = new CRC32();
			crc.update( label.getBytes() );
			int hue = (int)Math.abs( crc.getValue() % 16 );
			sb.append( "g.addNode( \""+label+"\", { render : render, size: "+size+", color: "+hue+"} );\n" );
			
		}
		vars.put( "nodeDefs", sb.toString() );
		sb = new StringBuilder();
		for( Entry<LabelEdge, Integer> entry : edges.entrySet() ) {
			sb.append( "g.addEdge( \""+entry.getKey().one+"\", \""+entry.getKey().two+"\", {  attraction: "+entry.getValue()+" } );\n" );
		}
		vars.put( "edgeDefs", sb.toString() );
		vars.put( "origin", label );
		
		response.renderOnLoadJavascript( tt.asString( vars ) );
	}
	
	private static <C> void inc( Map<C, Integer> map, C key ) {
		if( map.containsKey( key ) ) {
			map.put( key, map.get( key ) + 1 );
		} else {
			map.put( key, 1 );
		}
	}
	
}
